package benchmark.clients;

import generic.Request;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.sax.SAXSource;

import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;

import com.siemens.ct.exi.EXIFactory;
import com.siemens.ct.exi.GrammarFactory;
import com.siemens.ct.exi.api.sax.EXIResult;
import com.siemens.ct.exi.api.sax.EXISource;
import com.siemens.ct.exi.exceptions.EXIException;
import com.siemens.ct.exi.grammar.Grammar;
import com.siemens.ct.exi.helpers.DefaultEXIFactory;

import domainspecific.types.MeterReadings;

import benchmark.Client;

import org.apache.log4j.Logger;

public class ExiClient implements Client {

	private static final String host = "127.0.0.1";
	private static final int port = 1357;
	private InetSocketAddress address = null;
	private static final Logger exiLogger = Logger.getLogger("exilogger");
	
	private Socket socket = null;	
	private InputStream in = null;
	private OutputStream out = null;
	private EXIFactory exiFactory = null;

	public ExiClient() {
		this(ExiClient.host, ExiClient.port);
	}

	public ExiClient(String host, int port) {

		if(System.getenv().containsKey("READINGS_HOST")){
			host = System.getenv().get("READINGS_HOST");
		}
		
		if(System.getenv().containsKey("READINGS_PORT")){
			port = Integer.parseInt(System.getenv().get("READINGS_PORT"));
		}
		
		InetAddress hostAddr = null;
		
		try {
			hostAddr = InetAddress.getByName(host);
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		this.address = new InetSocketAddress(hostAddr, port);
		Socket socket = new Socket();
		try {
			socket.connect(this.address);
			out = socket.getOutputStream();
			in = socket.getInputStream();			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		GrammarFactory gf = GrammarFactory.newInstance();
		Grammar grammar;
		try {
			grammar = gf.createGrammar("exischema.xsd");
		} catch (EXIException e) {
			grammar = null;
			e.printStackTrace();
			System.err.println("Could not parse grammar: " + e.getMessage());
		}
		
		this.exiFactory = DefaultEXIFactory.newInstance();
		this.exiFactory.setGrammar(grammar);
	}

	@Override
	public void sendRequest() {
		try {
			// Establish connection
			

			// Write a request
			EXIResult exiResult = new EXIResult(this.exiFactory);
			exiResult.setOutputStream(out);
			JAXBContext jcontext = JAXBContext.newInstance(Request.class,
					MeterReadings.class);
			Marshaller marshal = jcontext.createMarshaller();
			// marshal.marshal(new Request(), out);
			Request request = new Request();
			long begin = System.currentTimeMillis();
			marshal.marshal(request, exiResult.getHandler());
			out.flush();

			// Now read the response
			EXISource saxSource = new EXISource(this.exiFactory);
			XMLReader xmlReader = saxSource.getXMLReader();
			SAXSource exiSource = new SAXSource(new InputSource(in));
			exiSource.setXMLReader(xmlReader);
			Unmarshaller unmarshal = jcontext.createUnmarshaller();

			MeterReadings response = (MeterReadings) unmarshal
					.unmarshal(exiSource);

			long finished = System.currentTimeMillis();
			long responseTime = (finished - begin);
			exiLogger.info("" + responseTime);

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (JAXBException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (EXIException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void finalize() {
		// Tear down the connection
		try {
			socket.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}
